package cc.iotkit.manager.task;

import cc.iotkit.common.thing.ThingModelMessage;
import cc.iotkit.common.utils.GpsCoordinateUtils;
import cc.iotkit.data.manager.IDeviceInfoData;
import cc.iotkit.manager.service.IMapService;
import cc.iotkit.model.device.DeviceDailyReport;
import cc.iotkit.model.device.DeviceInfo;
import cc.iotkit.temporal.IThingModelMessageData;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.google.common.util.concurrent.RateLimiter;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 上传设备轨迹
 */
@Component
public class UploadTraces {
    @Autowired
    private IThingModelMessageData thingModelMessageData;
    @Autowired
    private IDeviceInfoData deviceInfoData;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private IMapService mapService;
    private String LastTimeCacheKey="sync:upload_traces";
    private static Logger logger = LoggerFactory.getLogger(UploadTraces.class);

    @XxlJob("UploadTraces")
    public void run() throws Exception {
        logger.info("xxl-job:running UploadTraces...");
        try {
            AtomicBoolean isGps= new AtomicBoolean(false);//是否为GPS定位，优先使用GPS
            String startTime=getLastTime();
            String endTime= LocalDateTime.now().toString();
            List<ThingModelMessage> messageList = thingModelMessageData.findReports(startTime, endTime);
            AtomicReference<String> deviceId= new AtomicReference<>("");
            AtomicReference<String> tempDeviceId= new AtomicReference<>("");
            AtomicReference<DeviceInfo> deviceInfo=new AtomicReference<>();
            messageList.forEach(m -> {
                try {
                    isGps.set(false);
                    DeviceDailyReport r = JSONUtil.toBean(StrUtil.toCamelCase(m.getData().toString()), DeviceDailyReport.class);
                    List<Map<String, Object>> points = new ArrayList<>();
                    //优先使用gps
                    if (StringUtils.isNotEmpty(r.getLocations())) {
                        //如果GPS坐标不为0
                        String[] locations= r.getLocations().split(",");
                        if(!Float.valueOf(locations[0]).equals(0f)) {
                            isGps.set(true);
                            Map<String, Object> point = new HashMap<>();
                            //坐标系 WGS-84 to 火星坐标系 GCJ-02
                            double[] gcj02= GpsCoordinateUtils.calWGS84toGCJ02(Float.valueOf(locations[0]),Float.valueOf(locations[1]));
                            //转字符串
                            String loc= Arrays.stream(gcj02).mapToObj(String::valueOf).collect(Collectors.joining(","));
                            point.put("location", loc);
                            point.put("locatetime", m.getTime());
                            points.add(point);
                        }
                    }
                    //判断是否有硬件定位数据
                    if(!isGps.get()&&StringUtils.isNotEmpty(r.getHwPosition()))
                    {
                        logger.info(r.getDeviceId()+":使用硬件定位("+messageList.size()+")");
                        //设置QPS限制，限制为28次/s
                       /* RateLimiter limiter = RateLimiter.create(28);
                        if (limiter.tryAcquire())  {*/
                            Map<String, Object> hwPositionParam = (Map<String, Object>) JSONUtil.parse(r.getHwPosition());
                            Map<String, Object> result = mapService.getHWLocation(hwPositionParam);
                            if (result != null) {
                                //String[] loc = result.get("location").toString().split(",");
                                Map<String, Object> point = new HashMap<>();
                                point.put("location", result.get("location"));
                                point.put("locatetime", System.currentTimeMillis());
                                points.add(point);
                            }
                        /*} else {
                            logger.info("xxl-job-error:已达到限流");
                            XxlJobHelper.log("xxl-job-error:已达到限流");
                        }*/


                    }
                    if (points.size() > 0) {
                        deviceId.set(m.getDeviceId());
                        if (!deviceId.get().equals(tempDeviceId.get())) {
                            deviceInfo.set(deviceInfoData.findByDeviceId(deviceId.get()));
                            tempDeviceId.set(m.getDeviceId());
                        }
                        if (ObjectUtils.isNotEmpty(deviceInfo.get()))
                            mapService.uploadPoints(deviceInfo.get().getAmapTid(), deviceInfo.get().getAmapTrid(), points);
                    }
                }
                catch (Exception e){
                    logger.info("xxl-job-error:"+e.getMessage());
                    XxlJobHelper.log(e);
                }
            });

            //deviceDailyReportData.batchSave(reports);
            this.setLastTime(endTime);
            logger.info("xxl-job:running UploadTraces finished");
        }
        catch (Exception e){
            logger.info("xxl-job-error:"+e.getMessage());
            XxlJobHelper.log(e);
            XxlJobHelper.handleFail();
        }
    }

    public String getLastTime() {
        Object last = redisTemplate.opsForValue().get(LastTimeCacheKey);
        if(ObjectUtils.isEmpty(last)){
            Calendar c = Calendar.getInstance();
            return LocalDateTime.of(c.get(Calendar.YEAR),c.get(Calendar.MONTH),c.get(Calendar.DAY_OF_MONTH),0,0,0,1).toString();
        }
        return last.toString();
    }

    public void setLastTime(String lastTime) {
        redisTemplate.opsForValue().set(LastTimeCacheKey, lastTime);
    }
}
